//////////////////////////////////////////ok
#include"stdafx.h"
#include "bochs.h"



/* MOVSB ES:[EDI], DS:[ESI]   DS may be overridden
 *   mov string from DS:[ESI] into ES:[EDI]
 */
void IA32_CPU::MOVSB_XbYb(Ia32_Instruction_c *i)
{
  unsigned seg;
  Bit8u temp8;

  if (!IA32_NULL_SEG_REG(i->seg())) 
  {
    seg = i->seg();
  }
  else 
  {
    seg = IA32_SEG_REG_DS;
  }

  if (i->as32L())
  {
    Bit32u esi, edi;

    esi = ESI;
    edi = EDI;

    read_virtual_byte(seg, esi, &temp8);
    write_virtual_byte(IA32_SEG_REG_ES, edi, &temp8);

    if ( get_DF ()) 
	{
       esi--;
       edi--;
    }
    else 
	{
      esi++;
      edi++;
    }

    ESI = esi;
    EDI = edi;
  }
  else
  { 
    unsigned incr = 1;

    Bit16u si = SI;
    Bit16u di = DI;

    read_virtual_byte(seg, si, &temp8);
    write_virtual_byte(IA32_SEG_REG_ES, di, &temp8);

    if ( get_DF ()) 
	{
      si -= incr;
      di -= incr;
    }
    else 
	{
      si += incr;
      di += incr;
    }

    SI = si;
    DI = di;
  }
}

/* 16 bit opsize mode */
void IA32_CPU::MOVSW_XwYw(Ia32_Instruction_c *i)
{
  Bit16u temp16;
  unsigned seg;

  if (!IA32_NULL_SEG_REG(i->seg())) 
  {
    seg = i->seg();
  }
  else 
  {
    seg = IA32_SEG_REG_DS;
  }

  if (i->as32L()) 
  {

    Bit32u esi = ESI;
    Bit32u edi = EDI;

    read_virtual_word(seg, esi, &temp16);
    write_virtual_word(IA32_SEG_REG_ES, edi, &temp16);

    if ( get_DF ()) 
	{
      esi -= 2;
      edi -= 2;
    }
    else 
	{
      esi += 2;
      edi += 2;
    }

    ESI = esi;
    EDI = edi;
  }
  else
  {
    unsigned incr = 2;
    Bit16u si = SI;
    Bit16u di = DI;
    read_virtual_word(seg, si, &temp16);
    write_virtual_word(IA32_SEG_REG_ES, di, &temp16);

    if ( get_DF ()) 
	{
      si -= incr;
      di -= incr;
    }
    else 
	{
      si += incr;
      di += incr;
    }
    SI = si;
    DI = di;
  }
}

/* 32 bit opsize mode */
void IA32_CPU::MOVSD_XdYd(Ia32_Instruction_c *i)
{
  Bit32u temp32;
  unsigned seg;

  if (!IA32_NULL_SEG_REG(i->seg())) 
  {
    seg = i->seg();
  }
  else 
  {
    seg = IA32_SEG_REG_DS;
  }

  if (i->as32L())
  {
    unsigned incr = 4;
    Bit32u esi = ESI;
    Bit32u edi = EDI;
    read_virtual_dword(seg, esi, &temp32);
    write_virtual_dword(IA32_SEG_REG_ES, edi, &temp32);

    if ( get_DF ()) 
	{
      esi -= incr;
      edi -= incr;
    }
    else 
	{
      esi += incr;
      edi += incr;
    }

    ESI = esi;
    EDI = edi;
  }
  else
  { 
    Bit16u si = SI;
    Bit16u di = DI;
    read_virtual_dword(seg, si, &temp32);
    write_virtual_dword(IA32_SEG_REG_ES, di, &temp32);
    if ( get_DF ()) 
	{
      si -= 4;
      di -= 4;
    }
    else 
	{
      si += 4;
      di += 4;
    }

    SI = si;
    DI = di;
  }
}


void IA32_CPU::CMPSB_XbYb(Ia32_Instruction_c *i)
{
  unsigned seg;
  Bit8u op1_8, op2_8, diff_8;

  if (!IA32_NULL_SEG_REG(i->seg())) 
  {
    seg = i->seg();
  }
  else 
  {
    seg = IA32_SEG_REG_DS;
  }

  if (i->as32L()) 
  {
    Bit32u esi = ESI;
    Bit32u edi = EDI;
    read_virtual_byte(seg, esi, &op1_8);
    read_virtual_byte(IA32_SEG_REG_ES, edi, &op2_8);
    diff_8 = op1_8 - op2_8;
    IA32_SET_FLAGS_OSZAPC_8(op1_8, op2_8, diff_8, IA32_INSTR_COMPARE8);
    if ( get_DF ()) 
	{
      esi--;
      edi--;
    }
    else 
	{
      esi++;
      edi++;
    }

    EDI = edi;
    ESI = esi;
  }
  else
  { 
    Bit16u si = SI;
    Bit16u di = DI;
    read_virtual_byte(seg, si, &op1_8);
    read_virtual_byte(IA32_SEG_REG_ES, di, &op2_8);
    diff_8 = op1_8 - op2_8;
    IA32_SET_FLAGS_OSZAPC_8(op1_8, op2_8, diff_8, IA32_INSTR_COMPARE8);
    if ( get_DF ()) 
	{
      si--;
      di--;
    }
    else 
	{
      si++;
      di++;
    }

    DI = di;
    SI = si;
  }
}

/* 16 bit opsize mode */
void IA32_CPU::CMPSW_XwYw(Ia32_Instruction_c *i)
{
  Bit16u op1_16, op2_16, diff_16;
  unsigned seg;

  if (!IA32_NULL_SEG_REG(i->seg())) 
  {
    seg = i->seg();
  }
  else 
  {
    seg = IA32_SEG_REG_DS;
  }

  if (i->as32L()) 
  {
    Bit32u esi = ESI;
    Bit32u edi = EDI;
    read_virtual_word(seg, esi, &op1_16);
    read_virtual_word(IA32_SEG_REG_ES, edi, &op2_16);
    diff_16 = op1_16 - op2_16;
    IA32_SET_FLAGS_OSZAPC_16(op1_16, op2_16, diff_16, IA32_INSTR_COMPARE16);

    if ( get_DF ()) 
	{
      esi -= 2;
      edi -= 2;
    }
    else 
	{
      esi += 2;
      edi += 2;
    }

    EDI = edi;
    ESI = esi;
  }
  else
  {
    Bit16u si = SI;
    Bit16u di = DI;

    read_virtual_word(seg, si, &op1_16);
    read_virtual_word(IA32_SEG_REG_ES, di, &op2_16);
    diff_16 = op1_16 - op2_16;
    IA32_SET_FLAGS_OSZAPC_16(op1_16, op2_16, diff_16, IA32_INSTR_COMPARE16);
    if ( get_DF ()) 
	{
      si -= 2;
      di -= 2;
    }
    else 
	{
      si += 2;
      di += 2;
    }
    DI = di;
    SI = si;
  }
}

/* 32 bit opsize mode */
void IA32_CPU::CMPSD_XdYd(Ia32_Instruction_c *i)
{
  Bit32u op1_32, op2_32, diff_32;
  unsigned seg;

  if (!IA32_NULL_SEG_REG(i->seg())) 
  {
    seg = i->seg();
  }
  else 
  {
    seg = IA32_SEG_REG_DS;
  }

  if (i->as32L()) 
  {
    Bit32u esi = ESI;
    Bit32u edi = EDI;
    read_virtual_dword(seg, esi, &op1_32);
    read_virtual_dword(IA32_SEG_REG_ES, edi, &op2_32);
    diff_32 = op1_32 - op2_32;
    IA32_SET_FLAGS_OSZAPC_32(op1_32, op2_32, diff_32, IA32_INSTR_COMPARE32);
    if ( get_DF ()) 
	{
      esi -= 4;
      edi -= 4;
    }
    else 
	{
      esi += 4;
      edi += 4;
    }

    EDI = edi;
    ESI = esi;
  }
  else
  { /* 16 bit address mode */
    Bit16u si = SI;
    Bit16u di = DI;
    read_virtual_dword(seg, si, &op1_32);
    read_virtual_dword(IA32_SEG_REG_ES, di, &op2_32);
    diff_32 = op1_32 - op2_32;
    IA32_SET_FLAGS_OSZAPC_32(op1_32, op2_32, diff_32, IA32_INSTR_COMPARE32);

    if ( get_DF ()) 
	{
      si -= 4;
      di -= 4;
    }
    else 
	{
      si += 4;
      di += 4;
    }
    DI = di;
    SI = si;
  }
}


void IA32_CPU::SCASB_ALXb(Ia32_Instruction_c *i)
{
  Bit8u op1_8, op2_8, diff_8;

  op1_8 = AL;
  if (i->as32L()) 
  {
    Bit32u edi = EDI;
    read_virtual_byte(IA32_SEG_REG_ES, edi, &op2_8);
    diff_8 = op1_8 - op2_8;
    IA32_SET_FLAGS_OSZAPC_8(op1_8, op2_8, diff_8, IA32_INSTR_COMPARE8);

    if ( get_DF ()) 
	{
      edi--;
    }
    else 
	{
      edi++;
    }

    EDI = edi;
  }
  else
  { /* 16bit address mode */
    Bit16u di = DI;
    read_virtual_byte(IA32_SEG_REG_ES, di, &op2_8);
    diff_8 = op1_8 - op2_8;
    IA32_SET_FLAGS_OSZAPC_8(op1_8, op2_8, diff_8, IA32_INSTR_COMPARE8);

    if ( get_DF ()) 
	{
      di--;
    }
    else 
	{
      di++;
    }

    DI = di;
  }
}

/* 16 bit opsize mode */
void IA32_CPU::SCASW_AXXw(Ia32_Instruction_c *i)
{
  Bit16u op1_16, op2_16, diff_16;

  op1_16 = AX;

  if (i->as32L()) 
  {
    Bit32u edi = EDI;
    read_virtual_word(IA32_SEG_REG_ES, edi, &op2_16);
    diff_16 = op1_16 - op2_16;
    IA32_SET_FLAGS_OSZAPC_16(op1_16, op2_16, diff_16, IA32_INSTR_COMPARE16);

    if ( get_DF ()) 
	{
      edi -= 2;
    }
    else {
      edi += 2;
    }

    EDI = edi;
  }
  else
  { /* 16bit address mode */
    Bit16u di = DI;

    read_virtual_word(IA32_SEG_REG_ES, di, &op2_16);
    diff_16 = op1_16 - op2_16;
    IA32_SET_FLAGS_OSZAPC_16(op1_16, op2_16, diff_16, IA32_INSTR_COMPARE16);
    if ( get_DF ()) 
	{
      di -= 2;
    }
    else 
	{
      di += 2;
    }

    DI = di;
  }
}

/* 32 bit opsize mode */
void IA32_CPU::SCASD_EAXXd(Ia32_Instruction_c *i)
{
  Bit32u op1_32, op2_32, diff_32;
  op1_32 = EAX;

  if (i->as32L()) 
  {
    Bit32u edi = EDI;
    read_virtual_dword(IA32_SEG_REG_ES, edi, &op2_32);
    diff_32 = op1_32 - op2_32;
    IA32_SET_FLAGS_OSZAPC_32(op1_32, op2_32, diff_32, IA32_INSTR_COMPARE32);

    if ( get_DF ()) 
	{
      edi -= 4;
    }
    else 
	{
      edi += 4;
    }

    EDI = edi;
  }
  else
  { /* 16bit address mode */
    Bit16u di = DI;
    read_virtual_dword(IA32_SEG_REG_ES, di, &op2_32);
    diff_32 = op1_32 - op2_32;
    IA32_SET_FLAGS_OSZAPC_32(op1_32, op2_32, diff_32, IA32_INSTR_COMPARE32);

    if ( get_DF ()) 
	{
      di -= 4;
    }
    else 
	{
      di += 4;
    }

    DI = di;
  }
}


void IA32_CPU::STOSB_YbAL(Ia32_Instruction_c *i)
{
    Bit8u al = AL;

    unsigned incr = 1;
    Bit32u edi;

    if (i->as32L()) 
	{
      edi = EDI;
    }
    else
    { /* 16bit address size */
      edi = DI;
    }

    write_virtual_byte(IA32_SEG_REG_ES, edi, &al);

    if ( get_DF ()) 
	{
      edi -= incr;
    }
    else 
	{
      edi += incr;
    }

    if (i->as32L())
      EDI = edi;
    else
       DI = edi;

}

/* 16 bit opsize mode */
void IA32_CPU::STOSW_YwAX(Ia32_Instruction_c *i)
{
  Bit16u ax = AX;

 if (i->as32L()) 
  {
    Bit32u edi = EDI;
    write_virtual_word(IA32_SEG_REG_ES, edi, &ax);
    if ( get_DF ()) 
	{
      edi -= 2;
    }
    else 
	{
      edi += 2;
    }

    EDI = edi;
  }
  else
  { /* 16bit address size */
    Bit16u di = DI;
    write_virtual_word(IA32_SEG_REG_ES, di, &ax);

    if ( get_DF ()) 
	{
      di -= 2;
    }
    else 
	{
      di += 2;
    }

    DI = di;
  }
}

/* 32 bit opsize mode */
void IA32_CPU::STOSD_YdEAX(Ia32_Instruction_c *i)
{
  Bit32u eax = EAX;
  if (i->as32L())
  {
    Bit32u edi = EDI;
    write_virtual_dword(IA32_SEG_REG_ES, edi, &eax);

    if ( get_DF ()) 
	{
      edi -= 4;
    }
    else 
	{
      edi += 4;
    }

    EDI = edi;
  }
  else
  { /* 16bit address size */
    Bit16u di = DI;
    write_virtual_dword(IA32_SEG_REG_ES, di, &eax);
    if ( get_DF ()) 
	{
      di -= 4;
    }
    else 
	{
      di += 4;
    }

    DI = di;
  }
}


void IA32_CPU::LODSB_ALXb(Ia32_Instruction_c *i)
{
  unsigned seg;
  Bit8u al;

  if (!IA32_NULL_SEG_REG(i->seg())) 
  {
    seg = i->seg();
  }
  else 
  {
    seg = IA32_SEG_REG_DS;
  }

  if (i->as32L())
  {
    Bit32u esi = ESI;
    read_virtual_byte(seg, esi, &al);
    AL = al;
    if ( get_DF ()) 
	{
      esi--;
    }
    else 
	{
      esi++;
    }

    ESI = esi;
  }
  else
  { /* 16bit address mode */
    Bit16u si = SI;
    read_virtual_byte(seg, si, &al);
    AL = al;
    if ( get_DF ()) 
	{
      si--;
    }
    else 
	{
      si++;
    }

    SI = si;
  }
}

/* 16 bit opsize mode */
void IA32_CPU::LODSW_AXXw(Ia32_Instruction_c *i)
{
  unsigned seg;
  Bit16u ax;

  if (!IA32_NULL_SEG_REG(i->seg())) 
  {
    seg = i->seg();
  }
  else 
  {
    seg = IA32_SEG_REG_DS;
  }

  if (i->as32L())
  {
    Bit32u esi = ESI;
    read_virtual_word(seg, esi, &ax);
    AX = ax;

    if ( get_DF ()) 
	{
      esi -= 2;
    }
    else 
	{
      esi += 2;
    }

    ESI = esi;
  }
  else
  { /* 16bit address mode */
    Bit16u si = SI;
    read_virtual_word(seg, si, &ax);
    AX = ax;
    if ( get_DF ()) 
	{
      si -= 2;
    }
    else 
	{
      si += 2;
    }

    SI = si;
  }
}

/* 32 bit opsize mode */
void IA32_CPU::LODSD_EAXXd(Ia32_Instruction_c *i)
{
  unsigned seg;
  Bit32u eax;

  if (!IA32_NULL_SEG_REG(i->seg())) 
  {
    seg = i->seg();
  }
  else 
  {
    seg = IA32_SEG_REG_DS;
  }

  if (i->as32L())
  {
    Bit32u esi = ESI;
    read_virtual_dword(seg, esi, &eax);
    EAX = eax;
    if ( get_DF ()) 
	{
      esi -= 4;
    }
    else 
	{
      esi += 4;
    }

    ESI = esi;
  }
  else
  { /* 16bit address mode */
    Bit16u si = SI;
    read_virtual_dword(seg, si, &eax);
    EAX = eax;

    if ( get_DF ()) 
	{
      si -= 4;
    }
    else 
	{
      si += 4;
    }

    SI = si;
  }
}

